// 类: 类的组成：构造函数、属性（实例属性，原型属性、静态属性）、方法（实例的方法，原型的方法，静态方法）访问器，静态相关的配置

class Circle {
  // 给这个类来声明属性
  public x:number
  public y:number
  public fn: () => void
  constructor(x: number, y: number = 200) { // 函数
    this.x = x
    this.y = y
    this.fn = () => {}
  }
}
// 类的修饰符
// public 公开属性，类的实例在外部可以访问这个属性，类的内部也可以访问，继承的子类也可以访问
// protected（我自己能访问，儿子能访问，外部无法访问）
// private（私有的 自己能访问）

// 平时我们一般采用public 或者 private 的场景比较多

// readonly 标识仅读属性，意味着如果初始化后，不能被修改

// let circle = new Circle(100, 100)
new Circle(100, 100)

class Animal {
  // public name: string
  constructor(protected name: string) { // 等价于给每个属性添加了public
    this.name = name
  }
  // 原型方法 就是每一个实例共享的方法，父类提供的方法 子类是可以进行方法重写的
  // 原型的函数：void 意味着是不关心函数的返回值，并不是空的意思
  changeName(value: string, age: number) {
    this.name = value
  }
  // 原型属性 需要通过访问器来实现
  get aliasName() {
    return '$' + this.name
  }
  set aliasName(name: string) {
    this.name = name
  }
  static a = 1
  static getA() {
    return this.a
  }
}
// super在构造函数 指向的是父类，在原型的方法中调用的时候指向的是父类的原型
class Cat extends Animal {
  constructor(name: string, public readonly age: number) {
    super(name) // Animal.call(this)
    this.age = age
    // this.name
  }
  // 子类在重写父类方法要兼容，赋予的函数可以兼容父类
  changeName(value: string) {
    // this.name = value
    super.changeName(value, 100)
    return 'abc'
  }
}
const tom = new Cat('tom', 30)
tom.changeName('tonney')

// 以上用法同 es6

// super在 类中访问 constructor / static函数中指向的都是父类，在原型方法中，属性访问器都是 父类的原型

class Singleton {
  static instance = new Singleton() // 自己本身创造一个实例，后续一直用这一个，不产生多个
  protected constructor() {} // 增加protected 将构造函数不能被new
  static getInstance() {
    return this.instance
  }
}

// 类在什么时 不用外面new
let instance = Singleton.getInstance()

// ts 中有抽象类概念， abstract 不存在的
// 抽象类 可以含义非抽象的方法和属性，不会new它，抽象类可以被继承，抽象类中抽象方法子类必须要实现

{
  abstract class Animal {
    drink() {  // 非抽象，已经有实现了
      console.log('drink')
    }
    abstract eat():void // 抽象的方法，父类没有实现，那么子类必须实现
  }

  class Cat extends Animal {
    public a!:string
    eat():void {
      throw new Error('Method not implemented.')
    }

    // 因为我们编写代码的时候，慢慢的脱离继承了。组合优于继承。 累的装饰器（redux，nest，mobx）
  }
}

export {}
